// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:convert';
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';

class ScanResultTile extends StatelessWidget {
  const ScanResultTile({Key key, this.result, this.onTap}) : super(key: key);

  final ScanResult result;
  final VoidCallback onTap;

  Widget _buildTitle(BuildContext context) {
    if (result.device.name.length > 0) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(
            result.device.name,
//            overflow: TextOverflow.ellipsis,
          ),
          Text(
            result.device.id.toString(),
            style: Theme.of(context).textTheme.caption,
          )
        ],
      );
    } else {
      return Text(result.device.id.toString());
    }
  }

  Widget _buildAdvRow(BuildContext context, String title, String value) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(title, style: Theme.of(context).textTheme.caption),
          SizedBox(
            width: 12.0,
          ),
          Expanded(
            child: Text(
              value,
              style: Theme.of(context)
                  .textTheme
                  .caption
                  .apply(color: Colors.black),
              softWrap: true,
            ),
          ),
        ],
      ),
    );
  }

  String getNiceHexArray(List<int> bytes) {
    return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
        .toUpperCase();
  }

  String getNiceManufacturerData(Map<int, List<int>> data) {
    if (data.isEmpty) {
      return null;
    }
    List<String> res = [];
    data.forEach((id, bytes) {
      res.add(
          '${id.toRadixString(16).toUpperCase()}: ${getNiceHexArray(bytes)}');
    });
    return res.join(', ');
  }

  String getNiceServiceData(Map<String, List<int>> data) {
    if (data.isEmpty) {
      return null;
    }
    List<String> res = [];
    data.forEach((id, bytes) {
      res.add('${id.toUpperCase()}: ${getNiceHexArray(bytes)}');
    });
    return res.join(', ');
  }

  @override
  Widget build(BuildContext context) {
    return ExpansionTile(
      title: _buildTitle(context),
      leading: Text(result.rssi.toString()),
      trailing: RaisedButton(
        child: Text('CONNECT'),
        color: Colors.black,
        textColor: Colors.white,
        onPressed: (result.advertisementData.connectable) ? onTap : null,
      ),
      children: <Widget>[
        _buildAdvRow(
            context, 'Complete Local Name', result.advertisementData.localName),
        _buildAdvRow(context, 'Tx Power Level',
            '${result.advertisementData.txPowerLevel ?? 'N/A'}'),
        _buildAdvRow(
            context,
            'Manufacturer Data',
            getNiceManufacturerData(
                    result.advertisementData.manufacturerData) ??
                'N/A'),
        _buildAdvRow(
            context,
            'Service UUIDs',
            (result.advertisementData.serviceUuids.isNotEmpty)
                ? result.advertisementData.serviceUuids.join(', ').toUpperCase()
                : 'N/A'),
        _buildAdvRow(context, 'Service Data',
            getNiceServiceData(result.advertisementData.serviceData) ?? 'N/A'),
      ],
    );
  }
}

class ServiceTile extends StatelessWidget {
  final BluetoothService service;
  final List<CharacteristicTile> characteristicTiles;

  const ServiceTile({Key key, this.service, this.characteristicTiles})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (characteristicTiles.length > 0 &&
        service.uuid.toString() == '0000ffe0-0000-1000-8000-00805f9b34fb') {
      return ExpansionTile(
        title: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text('Service'),
            Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}',
                style: Theme.of(context)
                    .textTheme
                    .body1
                    .copyWith(color: Theme.of(context).textTheme.caption.color))
          ],
        ),
        children: characteristicTiles,
      );
    } else {
      return ListTile(
        title: Text('Service'),
        subtitle:
            Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}'),
      );
    }
  }
}

class PanelController extends StatefulWidget {
  final BluetoothDevice device;
  final BluetoothService service;

  PanelController({Key key, this.device, this.service}) : super(key: key);

  @override
  _PanelControllerState createState() => _PanelControllerState();
}

class _PanelControllerState extends State<PanelController> {
  String balance = '';
  BluetoothService serialService;

  Map<String, Map> keyboard = {
    'restart': {
      'start': 'KEY00on',
      'status': 'false',
      'stop': 'KEY00off',
    },
    'stop': {
      'start': 'KEY01on',
      'status': 'false',
      'stop': 'KEY01off',
    },
    'offset': {
      'start': 'KEY02on',
      'status': 'false',
      'stop': 'KEY02off',
    },
    'autoLevel': {
      'start': 'KEY03on',
      'status': 'false',
      'stop': 'KEY03off',
    },
    'autoDown': {
      'start': 'KEY04on',
      'status': 'false',
      'stop': 'KEY04off',
    },
    'leftFrontUp': {
      'start': 'KEY05on',
      'status': 'false',
      'stop': 'KEY05off',
    },
    'leftFrontDown': {
      'start': 'KEY06on',
      'status': 'false',
      'stop': 'KEY06off',
    },
    'rightFrontUp': {
      'start': 'KEY07on',
      'status': 'false',
      'stop': 'KEY07off',
    },
    'rightFrontDown': {
      'start': 'KEY08on',
      'status': 'false',
      'stop': 'KEY08off',
    },
    'leftRearUp': {
      'start': 'KEY09on',
      'status': 'false',
      'stop': 'KEY09off',
    },
    'leftRearDown': {
      'start': 'KEY10on',
      'status': 'false',
      'stop': 'KEY10off',
    },
    'rightRearUp': {
      'start': 'KEY11on',
      'status': 'false',
      'stop': 'KEY11off',
    },
    'rightRearDown': {
      'start': 'KEY12on',
      'status': 'false',
      'stop': 'KEY12off',
    },
  };

  List<int> _stringToBytes(String value) {
    List chars = utf8.encode(value);
    return chars;
//    return [
//      math.nextInt(255),
//      math.nextInt(255),
//      math.nextInt(255),
//      math.nextInt(255)
//    ];
  }

  Future<BluetoothService> _getSerialService() async {
    BluetoothService serialService;
//    if (device.isDiscoveringServices == "true"){
//
//    }
    List<BluetoothService> services = await widget.device.discoverServices();
    services.forEach((service) {
      if (service.uuid.toString() == '0000ffe0-0000-1000-8000-00805f9b34fb') {
        serialService = service;
      }
    });
    return serialService;
  }

  _orderBuildSend(String name, String rename) async {
    BluetoothService serialService = await _getSerialService();
    var characteristics = serialService.characteristics;
    for (BluetoothCharacteristic c in characteristics) {
      List<int> value1 = await c.read();
//      在Up和Down组合按键中，判断其逻辑
      if (keyboard[rename]['status'] == 'ture') {
//          其中一个按钮ON中，按下的按钮需要stop另一个状态，再发送start
        await c.write(_stringToBytes(keyboard[rename]['stop']));
        await c.write(_stringToBytes(keyboard[name]['start']));
        setState(() {
          keyboard[name]['status'] == 'false'
              ? keyboard[name]['status'] = 'ture'
              : keyboard[name]['status'] = 'false';
          keyboard[rename]['status'] == 'false'
              ? keyboard[rename]['status'] = 'ture'
              : keyboard[rename]['status'] = 'false';
        });
      } else {
        if (keyboard[name]['status'] == 'false') {
          await c.write(_stringToBytes(keyboard[name]['start']));
        } else {
          await c.write(_stringToBytes(keyboard[name]['stop']));
        }
        setState(() {
          keyboard[name]['status'] == 'false'
              ? keyboard[name]['status'] = 'ture'
              : keyboard[name]['status'] = 'false';
        });
      }

      await c.setNotifyValue(true);
      c.value.listen((value) {
        setState(() {
          balance = utf8.decode(value);
        });
//        balance = utf8.decode(value1);
        print(balance);
      });
    }
//    return null;
  }

  _orderSend(String name) async {
    BluetoothService serialService = await _getSerialService();
    var characteristics = serialService.characteristics;
    for (BluetoothCharacteristic c in characteristics) {
      List<int> value1 = await c.read();
      if (name == 'stop') {
        if (keyboard[name]['status'] == 'false') {
          await c.write(_stringToBytes(keyboard[name]['start']));
        } else {
          await c.write(_stringToBytes(keyboard[name]['stop']));
        }
        keyboard.forEach((String key,Map value) {
          setState(() {
            keyboard[key]['status'] = 'false';
          });
        });
      } else {
        await c.write(_stringToBytes(keyboard[name]['start']));
        keyboard.forEach((String key,Map value) {
          setState(() {
            keyboard[key]['status'] = 'false';
          });
        });
      }
      await c.setNotifyValue(true);
      c.value.listen((value) {
        setState(() {
          balance = utf8.decode(value);
        });
//        balance = utf8.decode(value1);
        print(balance);
      });
    }
//    return null;
  }

  Widget _buildAdjustButton(
      BuildContext context, String orderUp, String orderDown, String value) {
    return Row(
      children: <Widget>[
        Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            RaisedButton.icon(
              icon: Icon(Icons.arrow_drop_up),
              label: Text("Up"),
              color: keyboard[orderUp]['status'] == 'false'
                  ? Colors.grey
                  : Colors.red,
              onPressed: () => _orderBuildSend(orderUp, orderDown),
            ),
            Center(
              child: Text(
                value,
                style: TextStyle(
                  color: Colors.black,
                  fontWeight: FontWeight.w800,
                  fontFamily: 'Roboto',
                  letterSpacing: 0.5,
                  fontSize: 20,
                ),
              ),
            ),
            RaisedButton.icon(
              icon: Icon(Icons.arrow_drop_down),
              label: Text("Down"),
              color: keyboard[orderDown]['status'] == 'false'
                  ? Colors.grey
                  : Colors.red,
              onPressed: () => _orderBuildSend(orderDown, orderUp),
            ),
          ],
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        print('MyButton was tapped!');
      },
      child: Container(
//        height: 36.0,
        padding: const EdgeInsets.all(8.0),
        margin: const EdgeInsets.symmetric(horizontal: 8.0),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5.0),
//          color: Colors.lightGreen[500],
        ),
        child: Column(
          children: <Widget>[
            StreamBuilder<BluetoothDeviceState>(
              stream: widget.device.state,
              initialData: BluetoothDeviceState.connecting,
              builder: (c, snapshot) => Container(
                margin: EdgeInsets.fromLTRB(0, 10, 0, 20),
//                color: Colors.blue,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    (snapshot.data == BluetoothDeviceState.connected)
                        ? Icon(Icons.bluetooth_connected,
                            color: Colors.blue[500])
                        : Icon(Icons.bluetooth_disabled,
                            color: Colors.grey[500]),
                    RaisedButton.icon(
//                    color: Colors.lightGreen,
                      icon: Icon(Icons.power_settings_new),
                      label: Text("RESTART"),
                      onPressed: () => _orderSend('restart'),
                    ),
                    RaisedButton.icon(
                      color: Colors.red,
//                      color: keyboard['stop']['status'] == 'false'
//                          ? Colors.grey
//                          : Colors.red,
                      icon: keyboard['stop']['status'] == 'false'
                        ? Icon(Icons.stop)
                        : Icon(Icons.play_arrow),
                      label: Text("STOP"),
                      onPressed: () => _orderSend('stop'),
                    ),
                    StreamBuilder<bool>(
                      stream: widget.device.isDiscoveringServices,
                      initialData: false,
                      builder: (c, snapshot) => IndexedStack(
                        index: snapshot.data ? 1 : 0,
                        children: <Widget>[
                          IconButton(
                            icon: Icon(Icons.refresh),
                            onPressed: () => widget.device.discoverServices(),
                          ),
                          IconButton(
                            icon: SizedBox(
                              child: CircularProgressIndicator(
                                valueColor: AlwaysStoppedAnimation(Colors.grey),
                              ),
                              width: 18.0,
                              height: 18.0,
                            ),
                            onPressed: null,
                          )
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ),
            StreamBuilder<List<BluetoothService>>(
              stream: widget.device.services,
              initialData: [],
              builder: (c, snapshot) {
                return Container(
//                    color: Colors.blueGrey,
                  child: Column(
                    children: <Widget>[
//                      Text('列表'),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: [
                          Column(
                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                            children: [
                              Container(
//                  height: 180.0,
                                child: _buildAdjustButton(
                                    context,
                                    'leftFrontUp',
                                    'leftFrontDown',
                                    'LeftFront'),
                              ),
                              Container(
                                height: 180.0,
//                  child: _buildButton(),
                              ),
                              Container(
//                  height: 180.0,
                                child: _buildAdjustButton(context, 'leftRearUp',
                                    'leftRearDown', 'LeftRear'),
                              ),
                            ],
                          ),
                          Column(
                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                            children: [
                              Container(
//                  height: 180.0,
                                child: Column(
                                  mainAxisAlignment: MainAxisAlignment.start,
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: <Widget>[
                                    RaisedButton.icon(
                                      icon: Icon(Icons.arrow_forward_ios),
                                      label: Text("OFFSET"),
                                      onPressed: () => _orderSend('offset'),
                                    ),
                                    RaisedButton.icon(
                                      icon: Icon(Icons.arrow_forward_ios),
                                      label: Text("Auto Level"),
                                      onPressed: () =>
                                          _orderSend('autoLevel'),
                                    ),
                                    RaisedButton.icon(
                                      icon: Icon(Icons.arrow_forward_ios),
                                      label: Text("Auto Down"),
                                      onPressed: () =>
                                          _orderSend('autoDown'),
                                    ),
                                    Text('$balance'),
//                                StreamBuilder<List<BluetoothService>>(
//                                  stream: widget.device.services,
//                                  initialData: [],
//                                  builder: (c, snapshot) {
//                                    return Text(
//                                      _read(snapshot.data),
//
//                                    );
//                                  },
//                                ),
//                      Text(balance),
                                  ],
                                ),
                              ),
                            ],
                          ),
                          Column(
                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                            children: [
                              Container(
//                  height: 180.0,
                                child: _buildAdjustButton(
                                    context,
                                    'rightFrontUp',
                                    'rightFrontDown',
                                    'RightFront'),
                              ),
                              Container(
                                height: 180.0,
//                  child: _buildButton(),
                              ),
                              Container(
//                  height: 180.0,
                                child: _buildAdjustButton(
                                    context,
                                    'rightRearUp',
                                    'rightRearDown',
                                    'RightRear'),
                              ),
                            ],
                          ),
                        ],
                      ),
//                        Panel(snapshot.data),
                    ],
//                  children: _buildServiceTiles(snapshot.data),
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

class Panel extends StatelessWidget {
  final BluetoothService service;

//  final List<CharacteristicTile> characteristicTiles;

  const Panel({Key key, this.service}) : super(key: key);

  _orderSend(String name) async {
    var characteristics = service.characteristics;
    for (BluetoothCharacteristic c in characteristics) {
      List<int> value = await c.read();
      await c.write([0x12, 0x34]);
      await c.setNotifyValue(true);
      c.value.listen((value) {
        print(value);
      });
      print(value);
    }
//    return null;
  }

  Widget _buildAdjustButton(
      BuildContext context, String orderUp, String orderDown, String value) {
    return Row(
      children: <Widget>[
        Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            RaisedButton.icon(
              icon: Icon(Icons.arrow_drop_up),
              label: Text("Up"),
              onPressed: () => _orderSend(orderUp),
            ),
            Center(
              child: Text(
                value,
                style: TextStyle(
                  color: Colors.black,
                  fontWeight: FontWeight.w800,
                  fontFamily: 'Roboto',
                  letterSpacing: 0.5,
                  fontSize: 20,
                ),
              ),
            ),
            RaisedButton.icon(
              icon: Icon(Icons.arrow_drop_down),
              label: Text("Down"),
              onPressed: () => _orderSend(orderDown),
            ),
          ],
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        print('MyButton was tapped!');
      },
      child: Container(
//        height: 36.0,
        padding: const EdgeInsets.all(8.0),
        margin: const EdgeInsets.symmetric(horizontal: 8.0),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5.0),
//          color: Colors.lightGreen[500],
        ),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Container(
//                  height: 180.0,
                  child:
                      _buildAdjustButton(context, 'fdas', 'fdas', 'LeftFront'),
                ),
                Container(
                  height: 180.0,
//                  child: _buildButton(),
                ),
                Container(
//                  height: 180.0,
                  child: _buildAdjustButton(context, 'fd', 'fdas', 'LeftRear'),
                ),
              ],
            ),
            Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Container(
//                  height: 180.0,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      RaisedButton.icon(
                        icon: Icon(Icons.arrow_forward_ios),
                        label: Text("OFFSET"),
                        onPressed: () => print('fd'),
                      ),
                      RaisedButton.icon(
                        icon: Icon(Icons.arrow_forward_ios),
                        label: Text("Auto Level"),
                        onPressed: () => _orderSend('Auto Level'),
                      ),
                      RaisedButton.icon(
                        icon: Icon(Icons.arrow_forward_ios),
                        label: Text("Auto Down"),
                        onPressed: () => _orderSend('Auto Down'),
                      ),
                    ],
                  ),
                ),
              ],
            ),
            Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                Container(
//                  height: 180.0,
                  child:
                      _buildAdjustButton(context, 'fd', 'fdas', 'RightFront'),
                ),
                Container(
                  height: 180.0,
//                  child: _buildButton(),
                ),
                Container(
//                  height: 180.0,
                  child: _buildAdjustButton(context, 'fd', 'fdas', 'RightRear'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class CharacteristicTile extends StatelessWidget {
  final BluetoothCharacteristic characteristic;
  final List<DescriptorTile> descriptorTiles;
  final VoidCallback onReadPressed;
  final VoidCallback onWritePressed;
  final VoidCallback onNotificationPressed;

  const CharacteristicTile(
      {Key key,
      this.characteristic,
      this.descriptorTiles,
      this.onReadPressed,
      this.onWritePressed,
      this.onNotificationPressed})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<int>>(
      stream: characteristic.value,
      initialData: characteristic.lastValue,
      builder: (c, snapshot) {
        final value = utf8.decode(snapshot.data);
//        final value = snapshot.data;
        return ExpansionTile(
          title: ListTile(
            title: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text('Characteristic'),
                Text(
                    '0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}',
                    style: Theme.of(context).textTheme.body1.copyWith(
                        color: Theme.of(context).textTheme.caption.color))
              ],
            ),
            subtitle: Text(value.toString()),
            contentPadding: EdgeInsets.all(0.0),
          ),
          trailing: Row(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              IconButton(
                icon: Icon(
                  Icons.file_download,
                  color: Theme.of(context).iconTheme.color.withOpacity(0.5),
                ),
                onPressed: onReadPressed,
              ),
              IconButton(
                icon: Icon(Icons.file_upload,
                    color: Theme.of(context).iconTheme.color.withOpacity(0.5)),
                onPressed: onWritePressed,
              ),
              IconButton(
                icon: Icon(
                    characteristic.isNotifying
                        ? Icons.sync_disabled
                        : Icons.sync,
                    color: Theme.of(context).iconTheme.color.withOpacity(0.5)),
                onPressed: onNotificationPressed,
              )
            ],
          ),
          children: descriptorTiles,
        );
      },
    );
  }
}

class DescriptorTile extends StatelessWidget {
  final BluetoothDescriptor descriptor;
  final VoidCallback onReadPressed;
  final VoidCallback onWritePressed;

  const DescriptorTile(
      {Key key, this.descriptor, this.onReadPressed, this.onWritePressed})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text('Descriptor'),
          Text('0x${descriptor.uuid.toString().toUpperCase().substring(4, 8)}',
              style: Theme.of(context)
                  .textTheme
                  .body1
                  .copyWith(color: Theme.of(context).textTheme.caption.color))
        ],
      ),
      subtitle: StreamBuilder<List<int>>(
        stream: descriptor.value,
        initialData: descriptor.lastValue,
        builder: (c, snapshot) => Text(snapshot.data.toString()),
      ),
      trailing: Row(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          IconButton(
            icon: Icon(
              Icons.file_download,
              color: Theme.of(context).iconTheme.color.withOpacity(0.5),
            ),
            onPressed: onReadPressed,
          ),
          IconButton(
            icon: Icon(
              Icons.file_upload,
              color: Theme.of(context).iconTheme.color.withOpacity(0.5),
            ),
            onPressed: onWritePressed,
          )
        ],
      ),
    );
  }
}

class AdapterStateTile extends StatelessWidget {
  const AdapterStateTile({Key key, @required this.state}) : super(key: key);

  final BluetoothState state;

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.redAccent,
      child: ListTile(
        title: Text(
          'Bluetooth adapter is ${state.toString().substring(15)}',
          style: Theme.of(context).primaryTextTheme.subhead,
        ),
        trailing: Icon(
          Icons.error,
          color: Theme.of(context).primaryTextTheme.subhead.color,
        ),
      ),
    );
  }
}
